// A simple and buggy implementation of GNU GetText

#include "GNUGetText.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vector>

#ifdef WIN32
#include <windows.h>
#endif

static bool GetSystemLocale0(char* buf, int size) {
	char *s;

	s = getenv("LC_ALL");
	if (s && s[0]) {
		strncpy(buf, s, size);
		return true;
	}

	s = getenv("LC_MESSAGES");
	if (s && s[0]) {
		strncpy(buf, s, size);
		return true;
	}

	s = getenv("LANG");
	if (s && s[0]) {
		strncpy(buf, s, size);
		return true;
	}

	s = getenv("LANGUAGE");
	if (s && s[0]) {
		strncpy(buf, s, size);
		return true;
	}

#ifdef WIN32
	int i = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, buf, size);
	if (i > 0 && i < size) {
		int j = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, buf + i, size - i);
		if (j > 0) buf[i - 1] = '_';

		return true;
	}
#endif

	// TODO: ANDROID

	//shouldn't goes here
	printf("[GNUGetText] Error: GetSystemLocale() failed!\n");

	buf[0] = 0;
	return false;
}

bool GNUGetText::GetSystemLocale(char* buf, int size) {
	if (!GetSystemLocale0(buf, size)) return false;

	// TODO: IPHONEOS

	return true;
}

bool GNUGetText::LoadFileWithAutoLocale(const std::string& sFileName) {
	size_t nReplaceIndex;
	if ((nReplaceIndex = sFileName.find_first_of('*')) == std::string::npos) {
		return LoadFile(sFileName);
	}

	char buf[256];
	GetSystemLocale(buf, sizeof(buf));

	int lps = 0;

	for (;;) {
		if (buf[lps] == 0) break;

		int lpe = lps;

		while (buf[lpe] != ';' && buf[lpe] != ',' && buf[lpe] != ':' && buf[lpe] != 0) lpe++;
		bool bExit = (buf[lpe] == 0);
		buf[lpe] = 0;

		std::string str(buf + lps);
		std::string fn(sFileName);

		fn.replace(nReplaceIndex, 1, str);
		if (LoadFile(fn)) return true;

		size_t i = str.find_first_of('.'); //e.g. en_US.ISO_8859-1
		if (i != str.npos) {
			fn = sFileName;
			fn.replace(nReplaceIndex, 1, str.substr(0, i));
			if (LoadFile(fn)) return true;
		}

		i = str.find_first_of('@'); //e.g. sr@latin
		if (i != str.npos) {
			fn = sFileName;
			fn.replace(nReplaceIndex, 1, str.substr(0, i));
			if (LoadFile(fn)) return true;
		}

		i = str.find_first_of('_'); //e.g. de_DE
		size_t i2 = str.find_first_of('_', i + 1); //e.g. no_NO_NB
		if (i2 != str.npos) {
			fn = sFileName;
			fn.replace(nReplaceIndex, 1, str.substr(0, i2));
			if (LoadFile(fn)) return true;
		}
		if (i != str.npos) {
			fn = sFileName;
			fn.replace(nReplaceIndex, 1, str.substr(0, i));
			if (LoadFile(fn)) return true;
		}

		if (bExit) break;
		lps = lpe + 1;
	}

	return false;
}

bool GNUGetText::LoadFile(const std::string& sFileName) {
	FILE *f = fopen(sFileName.c_str(), "rb");
	if (f == NULL) return false;

	bool ret = false;

	int header[5];
	fread(header, 20, 1, f);
	// TODO: BIG ENDIAN

	if (header[0] == 0x950412DE && header[1] == 0) {
		m_objString.clear();
		m_sCurrentLocale.clear();

		if (header[2] > 0 && header[3] > 0 && header[4] > 0) {
			std::vector<int> OriginalString, TranslatedString;
			OriginalString.resize(header[2] * 2);
			TranslatedString.resize(header[2] * 2);

			fseek(f, header[3], SEEK_SET);
			fread(&(OriginalString[0]), header[2] * 8, 1, f);
			fseek(f, header[4], SEEK_SET);
			fread(&(TranslatedString[0]), header[2] * 8, 1, f);

			for (int i = 0; i < header[2]; i++) {
				std::string s1, s2;

				int length, offset;

				if ((length = (OriginalString[i * 2])) > 0
					&& (offset = (OriginalString[i * 2 + 1])) > 0)
				{
					fseek(f, offset, SEEK_SET);
					s1.resize(length);
					fread(&(s1[0]), length, 1, f);
				}

				if ((length = (TranslatedString[i * 2])) > 0
					&& (offset = (TranslatedString[i * 2 + 1])) > 0)
				{
					fseek(f, offset, SEEK_SET);
					s2.resize(length);
					fread(&(s2[0]), length, 1, f);
				}

				m_objString[s1] = s2;
			}
		}

		//update current locale
		m_sCurrentLocale = sFileName;
		std::string::size_type lps = m_sCurrentLocale.find_last_of("\\/");
		if (lps != std::string::npos) m_sCurrentLocale = m_sCurrentLocale.substr(lps + 1);
		lps = m_sCurrentLocale.find_last_of('.');
		if (lps != std::string::npos) m_sCurrentLocale = m_sCurrentLocale.substr(0, lps);

		ret = true;
	}

	fclose(f);

	return ret;
}

void GNUGetText::Close() {
	m_objString.clear();
	m_sCurrentLocale.clear();
}

std::string GNUGetText::GetText(const std::string& s) const {
	if (s.empty()) return s;

	std::map<std::string, std::string>::const_iterator it = m_objString.find(s);

	if (it == m_objString.end()) return s;
	else return it->second;
}
